<template>
  <canvas ref="canvas" style="width: 500px"></canvas>
  <input type="range" max="500" min="-100" v-model="range">
  {{ range}}
</template>

<script setup>
import { ref, onMounted } from 'vue'
import * as PIXI from 'pixi.js'

// 1. 获取画布元素
const canvas = ref(null)
const range = ref(0)

const pointAmount = 100
const baseSpeed = 0.025
const starStretch = 10
const starBaseSize = 0.1
let cameraZ = 0
const fov = 5
let speed = 0
let warpSpeed = 1
let deep = 500

// 3、创建光线
function createPointTexture(colors = []) {
  const c = document.createElement('canvas')
  c.width = 30
  c.height = 30
  const ctx = c.getContext('2d')
  const grd = ctx.createLinearGradient(0, 0, 0, c.width)
  
  colors.forEach(([offset, color]) => {
    grd.addColorStop(offset, color)
  })

  ctx.fillStyle = grd
  ctx.beginPath()
  // ctx.arc(x, y, radius, startAngle, endAngle, counterClockwise)
  // - counterClockwise 是否逆时针绘制
  const center = c.width / 2
  ctx.arc(center, center, center, 0, Math.PI * 2, true)
  ctx.closePath()
  ctx.fill()

  return PIXI.Texture.from(c)
}

function randomizePoint(point, initial) {
  point.z = initial 
    // ? Math.random() * deep 
    ? deep /  2
    : cameraZ + Math.random() * 1000 + deep
    // : cameraZ + deep
  const deg = Math.random() * Math.PI * 2
  // const distance = Math.random() * 50 + 1
  const distance = deep / 2 / 10
  point.x = Math.cos(deg) * distance
  point.y = Math.sin(deg) * distance
  point.deg = deg
}

onMounted(() => {
  // 2、设置基础背景
  const app = new PIXI.Application({
    view: canvas.value,
    width: deep,
    height: deep,
    resolution: window.devicePixelRatio,
    backgroundColor: 0x000000
  })

  // 4. 绘制点效果
  const pointColors = [
    [0, '#ffffff'],
    [1, '#0000ff']
  ]
  const pointTexture = createPointTexture(pointColors)

  // 
  const points = []
  for (let i = 0; i < pointAmount; i++) {
    const point = {
      sprite: new PIXI.Sprite(pointTexture),
      z: 0,
      x: 0,
      y: 0
    }
    // point.sprite.anchor.set(0.5, 0.7)
    randomizePoint(point, true)
    app.stage.addChild(point.sprite)
    // graphics.addChild(point.sprite)
    points.push(point)
  }

  app.ticker.add(delta => {
    speed += (warpSpeed - speed) / 20
    // cameraZ += delta * 10 * (speed + baseSpeed)
    cameraZ = range.value

    const _w = app.renderer.screen.width
    const _h = app.renderer.screen.height

    for(let i = 0; i < pointAmount; i++) {
      const point = points[i]

      if (point.z < cameraZ) randomizePoint(point)

      // 使用非常简单的投影将星形 3d 位置映射到 2d
      const z = point.z - cameraZ

      point.sprite.x = point.x * (fov / z) * _w + _w / 2
      // point.sprite.x = point.x + Number(range.value) * Math.cos(point.deg)
      point.sprite.y = point.y * (fov / z) * _w + _h / 2
      // point.sprite.y = point.y + Number(range.value) * Math.sin(point.deg)
      // 计算星标和旋转。
      const dxCenter = point.sprite.x - _w / 2
      const dyCenter = point.sprite.y - _h / 2
      const distanceCenter = Math.sqrt(dxCenter * dxCenter + dyCenter * dyCenter)
      const distanceScale = Math.max(0, (deep - z) / deep)
      point.sprite.scale.x = distanceScale * starBaseSize
      // point.sprite.scale.x = .3
      // 星星朝向中心，因此 y 轴朝向中心。
      // 根据我们移动的速度、拉伸因子是多少以及它离中心多远来缩放星星。
      // point.sprite.scale.y = 3
      point.sprite.scale.y = distanceScale * starBaseSize 
        + distanceScale * starStretch * speed * distanceCenter / _w
      point.sprite.rotation = Math.atan2(dyCenter, dxCenter) + Math.PI / 2
    }
  })
})
</script>